﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace remes.BLoc
{
   public class TranslationSet : INotifyPropertyChanged
   {
      public TranslationSet()
      {
         FileName = null;
         TargetLanguages = new ObservableCollection<string>();
         Entries = new Dictionary<string, TranslationEntry>();
      }

      public string FileName { get; private set; }

      public IDictionary<string, TranslationEntry> Entries { get; private set; }

      public IList<string> TargetLanguages { get; private set; }

      private string _SelectedLang = null;

      public string SelectedLang
      {
         get { return _SelectedLang; }
         set
         {
            _SelectedLang = value;
            foreach (var entry in Entries.Values)
            {
               entry.SelectedLangChanged();
            }
            NotifyPropertyChnaged("SelectedLang");
         }
      }

      public void Load(string path)
      {
         TargetLanguages.Clear();
         Entries.Clear();

         FileName = path;
         var xDoc = XDocument.Load(path);

         foreach (var xLang in xDoc.Root.Elements("TargetLanguage"))
         {
            AddTargetLanguage(xLang.Value);
         }

         foreach (var xEntry in xDoc.Root.Elements("Entry"))
         {
            Entries.Add((string)xEntry.Attribute("StreamName") + ";" + (string)xEntry.Attribute("Key"), new TranslationEntry(this, xEntry));
         }
      }

      public string AddTargetLanguage(string language)
      {
         // check if is valid language
         var ci = new CultureInfo(language);

         // check if already exists
         foreach (var lang in TargetLanguages)
         {
            if (string.Compare(lang, ci.Name, StringComparison.OrdinalIgnoreCase) == 0)
            {
               return ci.Name;
            }
         }
         TargetLanguages.Add(ci.Name);
         return ci.Name;
      }

      public void RemoveTargetLanguage(string language)
      {
         var ci = new CultureInfo(language);
         language = ci.Name;

         foreach (var entry in Entries.Values)
         {
            if (entry.Texts.ContainsKey(language))
            {
               entry.Texts.Remove(language);
            }
         }
         TargetLanguages.Remove(language);
      }

      public void Save()
      {
         if (String.IsNullOrEmpty(FileName))
         {
            throw new InvalidOperationException("Can not save without a file name!");
         }
         SaveAs(FileName);
      }

      public void SaveAs(string path)
      {
         FileName = path;

         var xDoc = new XDocument(new XElement("BLocTranslation"));

         foreach (var lang in TargetLanguages)
         {
            xDoc.Root.Add(new XElement("TargetLanguage", lang));
         }

         foreach (var entry in Entries.Values)
         {
            var xEntry = new XElement("Entry");
            entry.Save(xEntry);
            xDoc.Root.Add(xEntry);
         }

         xDoc.Save(path);
      }

      public void MergeLocBamlFile(string mergeFile, string origLang)
      {
         var xMergeFile = XDocument.Load(mergeFile);

         var origLangCulture = CultureInfo.GetCultureInfo(origLang);

         // merge parsed entries into set
         foreach (var xMergeEntry in xMergeFile.Root.Elements("Entry"))
         {
            var streamName = (string)xMergeEntry.Attribute("StreamName");
            var key = (string)xMergeEntry.Attribute("Key");
            var origText = (string)xMergeEntry.Attribute("Content");

            TranslationEntry entry;
            if (Entries.TryGetValue(streamName + ";" + key, out entry))
            {
               entry.Category = (string)xMergeEntry.Attribute("Caregory");
               entry.IsReadable = Boolean.Parse((string)xMergeEntry.Attribute("Readable"));
               entry.IsModifiable = Boolean.Parse((string)xMergeEntry.Attribute("Modifiable"));
               entry.Comments = (string)xMergeEntry.Attribute("Comments");
               entry.IsDeleted = false;

               if (String.Compare(origText, entry.OriginalText, false, origLangCulture) != 0)
               {
                  // if there is a text in original language and the text is the same
                  // as the old original text, then update it to the new original text
                  foreach (var text in entry.Texts.Values)
                  {
                     if (String.Compare(origLang, text.Language, StringComparison.OrdinalIgnoreCase) == 0
                        && String.Compare(entry.OriginalText, text.Text, false, origLangCulture) == 0)
                     {
                        text.Text = origText;
                     }
                     text.State = TranslationTextState.OriginalTextChanged;
                  }

                  entry.OriginalText = origText;
                  entry.OriginalLanguage = origLang;
               }
            }
            else
            {
               entry = new TranslationEntry(this, streamName, key)
                  {
                     Category = (string)xMergeEntry.Attribute("Caregory"),
                     IsReadable = Boolean.Parse((string)xMergeEntry.Attribute("Readable")), 
                     IsModifiable = Boolean.Parse((string)xMergeEntry.Attribute("Modifiable")),
                     Comments = (string)xMergeEntry.Attribute("Comments"), 
                     OriginalText = origText, 
                     OriginalLanguage = origLang,
                  };

               Entries.Add(streamName + ";" + key, entry);
            }
         }

         // label deleted entries
         foreach (var entry in Entries.Values)
         {
            var xMergeEntry = (from e in xMergeFile.Root.Elements("Entry")
                               where (string)e.Attribute("StreamName") == entry.StreamName && (string)e.Attribute("Key") == entry.Key
                               select e).FirstOrDefault();
            if (xMergeEntry == null)
            {
               entry.IsDeleted = true;
            }
         }
      }

      #region INotifyPropertyChanged Members

      protected void NotifyPropertyChnaged(string propertyName)
      {
         var temp = PropertyChanged;
         if (temp != null)
         {
            temp(this, new PropertyChangedEventArgs(propertyName));
         }
      }

      public event PropertyChangedEventHandler PropertyChanged;

      #endregion
   }
}
